"use strict";
exports.__esModule = true;
var validator_1 = require("./validator");
var object_1 = require("../utils/object");
var toString = Object.prototype.toString;
var validateSingleRule = function (rule, value, param, models) {
    if (param === void 0) { param = null; }
    if (models === void 0) { models = null; }
    var message = '';
    var ruleKeys = Object.keys(rule);
    for (var i = 0, l = ruleKeys.length; i < l; ++i) {
        var ruleKey = ruleKeys[i];
        if (ruleKey === 'name' || ruleKey === 'message')
            continue;
        var validateMethod = typeof rule.validator !== 'undefined' ? rule.validator : validator_1["default"][ruleKey];
        if (typeof validateMethod === 'function') {
            message = validateMethod(rule, value, param, models);
            if (message) {
                return message;
            }
        }
    }
    return message;
};
var FormValidator = /** @class */ (function () {
    function FormValidator(models, rules) {
        this.models = models;
        this.rules = rules;
        this.errors = {};
    }
    FormValidator.prototype.validate = function (cb) {
        var _this = this;
        return new Promise(function (resolve) {
            var failCount = 0;
            var errors = _this.errors;
            var models = _this.models;
            // let errorChanged = false
            Object.keys(_this.rules).forEach(function (fieldName) {
                var oldError = errors[fieldName];
                _this._innerValidateField(fieldName, models[fieldName], function (valid, newError) {
                    if (!valid)
                        failCount++;
                    if ((0, object_1.diff)(oldError, newError)) {
                        errors[fieldName] = newError;
                        // errorChanged = true
                    }
                });
            });
            var keys = Object.keys(errors);
            keys.forEach(function (key) {
                if (!errors[key])
                    delete errors[key];
            });
            // 先支持同步的接口吧
            resolve({ isValid: !failCount, errors: failCount ? errors : undefined });
            cb && cb(!failCount, failCount ? errors : undefined);
        });
    };
    FormValidator.prototype.validateField = function (name, value, cb) {
        var _this = this;
        return new Promise(function (resolve) {
            _this._innerValidateField(name, value, function (valid, error) {
                var errObj = {};
                errObj[name] = error;
                resolve({ valid: valid, error: valid ? undefined : error });
                cb && cb(valid, valid ? undefined : errObj);
                var oldError = _this.errors[name];
                var errorChanged = (0, object_1.diff)(oldError, error);
                if (errorChanged) {
                    if (!error)
                        delete _this.errors[name];
                    _this.errors[name] = error;
                }
            });
        });
    };
    FormValidator.prototype._innerValidateField = function (name, value, cb) {
        var rules = this.rules[name];
        if (!rules) {
            console.warn("[form-validator] rule name ".concat(name, " not exists."));
            cb(true);
            return;
        }
        // 处理参数
        if (typeof value === 'function') {
            cb = value;
            value = undefined;
        }
        var isFail = false;
        var models = this.models;
        if (toString.call(rules) === '[object Array]') {
            rules.forEach(function (rule) {
                rule.name = name; // 字段名称
                var resMessage = validateSingleRule(rule, value || models[name], rule.param, models);
                // 失败了直接中止
                if (resMessage && !isFail) {
                    isFail = true;
                    // errors[name] = {message: resMessage}
                    var error = resMessage ? { message: resMessage, rule: rule } : undefined;
                    cb(false, error);
                }
            });
            // 成功的回调
            if (!isFail) {
                cb(!isFail);
            }
        }
        else {
            var rule = rules;
            rule.name = name;
            var resMessage = validateSingleRule(rule, value || models[name], rule.param, models);
            var error = resMessage ? { message: resMessage, rule: rule } : undefined;
            if (resMessage) {
                isFail = true;
            }
            cb(!isFail, error);
        }
    };
    FormValidator.addMethod = function (ruleName, method) {
        validator_1["default"][ruleName] = method;
    };
    FormValidator.prototype.setModel = function (newModel) {
        this.models = newModel;
    };
    FormValidator.prototype.setRules = function (newRules) {
        this.rules = newRules;
    };
    return FormValidator;
}());
exports["default"] = FormValidator;
